package com.grakol.parallel.samples;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Implements runnable task that includes 1 function. 
 * The task should run in a thread along with several other parallel tasks. 
 * After the thread starts, the task waits at the barrier point until all 
 * other associated parallel tasks reach this point. Then, it calls the 
 * function to perform its operations. The getResult() method blocks until the 
 * function returns.
 * 
 * @author LK
 *
 * @param <R> - result type.
 */
public class RunnableTask<R> implements Runnable {
	private CyclicBarrier _barrier;
	private AtomicBoolean _done = new AtomicBoolean();
	private IFunction<R> _function;

	/**
	 * Constructs RunnableTask for a given function and using a given 
	 * pre-configured barrier for start time synchronization.
	 * 
	 * @param function the given function.
	 * @param barrier the given pre-configured barrier.
	 */
	public RunnableTask( IFunction<R> function, CyclicBarrier barrier ) {
		_function = function;
		_barrier = barrier;
	}
	/**
	 * Runs the task. The actual start time is synchronized with other 
	 * associated tasks by using CyclicBarrier.
	 */
	@Override
	public void run() {
		synchronized( this ) {
			try {
				_barrier.await();
			} catch( Exception e ) {}
			_function.perform();
		}
		synchronized( this ) {
			_done.set( true );
			notify();
		}
	}
	/**
	 * Blocks until the specified function finished. Returns results.
	 * 
	 * @return results after the specified function finished.
	 */
	public synchronized R getResult() {
		if( ! _done.get() ) {
			try {
				wait();
			} catch( Exception e ) {}
		}
		return _function.getResult();
	}
}
